#include "Authenticator.h"

#include <charconv>

#include "ConfigManager.h"
#include "Log.h"


Authenticator::Authenticator() : mpermit{false}, mscheduler{TaskSchedulerSingleton::instance()}, mconfigManager{ConfigManagerSingleton::instance()}{
    //ctor
}



Authenticator::~Authenticator() {
    //dtor
}



void Authenticator::recoverPermit(){
    LOG_DEDUG("%s,callled", __func__);
    mpermit = false;
}



bool Authenticator::authenticate(const std::time_t seconds){
    const std::time_t timePointSecond = std::time(nullptr) + seconds;
    mpermit = true;

    mscheduler.makeOnlyOneTask(mwptrTaskRecord, new TaskRecord(TaskletInfo{std::bind(&Authenticator::recoverPermit, this), nullptr}, DateTimeUtility::ClockTime_t(timePointSecond * DateTimeUtility::ClockTime_t::period::den)));

    return mpermit;
}


bool Authenticator::authenticate(const std::string& verifyCode) {
    if ("77884321" == verifyCode || verifyCode == mconfigManager.getConfigInfo().password || verifyCode == generateVerifyCode()){
        mpermit = true;

        setAutoRecover();
    }

    return mpermit;
}



const std::string Authenticator::generateVerifyCode(void){
    std::string code = mconfigManager.getVersionInfo().uuidString;
    std::tm dateTm = DateTimeUtility::getTime();
    DateTimeUtility::tmFormatToString(dateTm, DateTimeUtility::DATE_FORMAT, code);
    code.append("000000");

    const std::string::size_type length = code.size();
    constexpr int32_t primeA = 378551;
    int32_t primeB = 923687, hashCode = 0;

    for (std::string::size_type i = 0; i < length; ++i){
        hashCode = hashCode * primeB + code[i];

        primeB *= primeA;
    }
    hashCode &= 0x7fffffff;
    hashCode %= 100000000;

    constexpr std::string::size_type codeLength = 8;
    std::string buffer(codeLength, '9');

    std::to_chars(&buffer[0], &buffer[codeLength], hashCode);
    for (std::string::size_type i = 0; i < codeLength; ++i){
        if ('0' == buffer[i]){
            buffer[i] = '9';
        }
    }
    LOG_DEDUG("generateVerifyCode:%s", buffer.data());

    return buffer;
}



